library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
use WORK.COMMON.ALL;

entity Core is
port (
	CLK_MAIN, CLK_11, CLK_25, CLK_100, RST: in std_logic;
	CMD: in std_logic_vector(3 downto 0);
	NEW_TRUNK: in ITrunk;
	NOW_PLAYER: in std_logic;
	NOW_CUT: in std_logic;
	NOW_TRUNKS: in ITrunkList;
	NOW_HP: in std_logic_vector(9 downto 0);
	NOW_SCORE: in std_logic_vector(9 downto 0);
	NOW_TIMER: in std_logic_vector(31 downto 0);
	NEW_PLAYER: out std_logic;
	NEW_CUT: out std_logic;
	NEW_TRUNKS: out ITrunkList;
	NEW_HP: out std_logic_vector(9 downto 0);
	NEW_SCORE: out std_logic_vector(9 downto 0);
	NEW_TIMER: out std_logic_vector(31 downto 0)
);
end Core;

architecture Core_bhv of Core is
begin
	process(CLK_MAIN, RST)
		variable temp_timer, new_ok_hp, new_fail_hp: integer;
	begin
		temp_timer := CONV_INTEGER(NOW_TIMER) + 1;
		new_ok_hp := CONV_INTEGER(NOW_HP) + HP_OFFSET;
		new_fail_hp := CONV_INTEGER(NOW_HP) - CONV_INTEGER(NOW_SCORE)/10 - 1;
		
		if RST='1' then
			NEW_PLAYER <= PLAYER_LEFT;
			NEW_CUT <= PLAYER_CUT_NONE;
			NEW_TRUNKS <= (others => TRUNK_N);
			NEW_HP <= HP_RESTART;
			NEW_SCORE <= (others => '0');
			NEW_TIMER <= (others => '0');
			
		elsif CLK_MAIN'event and CLK_MAIN='1' then
			if CMD=CMD_KEEP then
				NEW_PLAYER <= NOW_PLAYER;
				NEW_CUT <= PLAYER_CUT_NONE;
				NEW_TRUNKS <= NOW_TRUNKS;
				NEW_HP <= NOW_HP;
				NEW_SCORE <= NOW_SCORE;
				NEW_TIMER <= NOW_TIMER;
				
			elsif CMD=CMD_NONE then
				NEW_PLAYER <= NOW_PLAYER;
				if NOW_CUT = PLAYER_CUT_ING then
					if NOW_TIMER > TIMER_INTERVAL then
						NEW_CUT <= PLAYER_CUT_NONE;
						NEW_TIMER <= (others => '0');
					else
						NEW_CUT <= PLAYER_CUT_ING;
						NEW_TIMER <= NOW_TIMER + 1;
					end if;
				else
					NEW_CUT <= PLAYER_CUT_NONE;
					NEW_TIMER <= NOW_TIMER + 1;
				end if;
				if NOW_HP = HP_RESTART then
					NEW_TRUNKS <= NEW_TRUNK & NOW_TRUNKS(9 downto 1);
					if NOW_TIMER = TRUNK_MAXN-1 then
						NEW_HP <= HP_MAXN;
					else
						NEW_HP <= NOW_HP;
					end if;
				else
					NEW_TRUNKS <= NOW_TRUNKS;
					if temp_timer MOD TIMER_HP = 0 then
						if new_fail_hp < 0 then
							NEW_HP <= HP_ZERO;
						else
							NEW_HP <= CONV_STD_LOGIC_VECTOR(new_fail_hp, 10);
						end if;
					else
						NEW_HP <= NOW_HP;
					end if;
				end if;
				
				NEW_SCORE <= NOW_SCORE;
				
			elsif CMD=CMD_PLAYER_LEFT then
				NEW_PLAYER <= PLAYER_LEFT;
				NEW_TIMER <= NOW_TIMER;
				if NOW_TRUNKS(0) = TRUNK_L OR NOW_TRUNKS(0) = TRUNK_DL then
					NEW_CUT <= PLAYER_CUT_NONE;
					NEW_HP <= HP_ZERO;
					NEW_SCORE <= NOW_SCORE;
					NEW_TRUNKS <= NOW_TRUNKS;
				elsif NOW_TRUNKS(0) = TRUNK_DR then
					NEW_CUT <= PLAYER_CUT_ING;
					NEW_HP <= NOW_HP;
					NEW_TIMER <= (others => '0');
					NEW_SCORE <= NOW_SCORE;
					NEW_TRUNKS <= NOW_TRUNKS(9 downto 1) & TRUNK_R;
				else
					if NOW_TRUNKS(1) = TRUNK_L OR NOW_TRUNKS(1) = TRUNK_DL then
						NEW_CUT <= PLAYER_CUT_NONE;
						NEW_SCORE <= NOW_SCORE;
						NEW_HP <= HP_ZERO;
					else
						NEW_CUT <= PLAYER_CUT_ING;
						NEW_SCORE <= NOW_SCORE + 1;
						if new_ok_hp >= HP_MAXN then
							NEW_HP <= HP_MAXN;
						else
							NEW_HP <= CONV_STD_LOGIC_VECTOR(new_ok_hp, 10);
						end if;
						NEW_TIMER <= (others => '0');
					end if;
					NEW_TRUNKS <= NEW_TRUNK & NOW_TRUNKS(TRUNK_MAXN-1 downto 1);
				end if;
				
			elsif CMD=CMD_PLAYER_RIGHT then
				NEW_PLAYER <= PLAYER_RIGHT;
				NEW_TIMER <= NOW_TIMER;
				if NOW_TRUNKS(0) = TRUNK_R OR NOW_TRUNKS(0) = TRUNK_DR then
					NEW_CUT <= PLAYER_CUT_NONE;
					NEW_HP <= HP_ZERO;
					NEW_SCORE <= NOW_SCORE;
					NEW_TRUNKS <= NOW_TRUNKS;
				elsif NOW_TRUNKS(0) = TRUNK_DL then
					NEW_CUT <= PLAYER_CUT_ING;
					NEW_HP <= NOW_HP;
					NEW_TIMER <= (others => '0');
					NEW_SCORE <= NOW_SCORE;
					NEW_TRUNKS <= NOW_TRUNKS(9 downto 1) & TRUNK_L;
				else
					if NOW_TRUNKS(1) = TRUNK_R OR NOW_TRUNKS(1) = TRUNK_DR then
						NEW_CUT <= PLAYER_CUT_NONE;
						NEW_SCORE <= NOW_SCORE;
						NEW_HP <= HP_ZERO;
					else
						NEW_CUT <= PLAYER_CUT_ING;
						NEW_SCORE <= NOW_SCORE + 1;
						if new_ok_hp >= HP_MAXN then
							NEW_HP <= HP_MAXN;
						else
							NEW_HP <= CONV_STD_LOGIC_VECTOR(new_ok_hp, 10);
						end if;
						NEW_TIMER <= (others => '0');
					end if;
					NEW_TRUNKS <= NEW_TRUNK & NOW_TRUNKS(TRUNK_MAXN-1 downto 1);
				end if;
				
			elsif CMD=CMD_RESTART then
				NEW_PLAYER <= PLAYER_LEFT;
				NEW_CUT <= PLAYER_CUT_NONE;
				NEW_TRUNKS <= (others => TRUNK_N);
				NEW_HP <= HP_RESTART;
				NEW_SCORE <= (others => '0');
				NEW_TIMER <= (others => '0');
				
			end if;
		end if;
	end process;
end Core_bhv;
